首页 > 试题广场 >

链表中的节点每k个一组翻转

[编程题]链表中的节点每k个一组翻转
  • 热度指数:252329 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
将给出的链表中的节点每 k 个一组翻转,返回翻转后的链表
如果链表中的节点数不是 k 的倍数,将最后剩下的节点保持原样
你不能更改节点中的值,只能更改节点本身。

数据范围: ,链表中每个元素都满足
要求空间复杂度 ,时间复杂度
例如:
给定的链表是
对于 , 你应该返回
对于 , 你应该返回

示例1

输入

{1,2,3,4,5},2

输出

{2,1,4,3,5}
示例2

输入

{},1

输出

{}

说明:本题目包含复杂数据结构ListNode,点此查看相关信息
// 递归做法
// 含义:返回以head开头的链表经k组反转后的首节点指针
function reverseKGroup(head, k){
    let tail = head;
    for(let i = 0; i<k; i++){
        if(!tail){
            return head;
        }
        tail = tail.next;
    }
    // 区间反转
    let l = null;
    let r = head;
    for(let i = 0; i<k; i++){
        const temp = r.next;
        r.next = l;
        l = r;
        r = temp;
    }
    // 递归调用
    head.next = reverseKGroup(r,k);
    return l;
}

//常规做法
function reverseKGroup( head ,  k ) {
    if(!head || !head.next || k === 1){
        return head;
    }

    let left = head;
    let right;
    const dummy = new ListNode(-1);
    let tail = dummy;
    tail.next = head;
    while(left){
        // 确定反转区间【left,right】
        right = left;
        for(let i = 1; i< k; i++){
            right = right.next;
            if(!right){
                right = null;
                break;
            }
        }
        // 链表不足k个节点
        if(!right){
            tail.next = left;
            break;
        }

        // 反转k个节点[left,right] 算法
        let l = null;
        let r = left;
        for(let i = 0; i<k; i++){
            const temp = r.next;
            r.next = l;
            l = r;
            r = temp;
        }

        // 将本组与上一组连接
        tail.next = l;
        tail = left;
        left = r;
    }
    head = dummy.next;
    return head;
}

发表于 2023-08-12 10:29:28 回复(0)
根据官方解题思路用递归重写,代码简洁很多
 function reverseKGroup( head ,  k ) {
    if(k === 1 || head === null) return head;
    let tail = head;
    let pre = null;
    let cur = head;
    let root = null;
    // 每次从进入函数的头节点优先遍历链表k次,分出一组
    for (let i = 1; i <= k; i++) {
        tail = tail.next;
        if (tail === null && i < k) return head; // 不足k不用反转直接返回头
    }
    // 从进入函数的头节点开始,依次反转接下来的一组链表
    for (let i = 1; i <= k; i++) {
        let temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
    }
    // 一组经过反转后,小组的根结点找到了,且原来的头变成了尾,后面接下一组的反转结果
    root = pre;
    head.next = reverseKGroup(tail, k);
    // 每一级要返回的就是翻转后的这一分组的头,以及连接好它后面所有翻转好的分组链表。
    return root;
 }



顺便也附上最初的复杂的版本
function reverseKGroup( head ,  k ) {
    if(k === 1 || head === null || head.next === null) return head;
    let pre = null; // 移动指针
    let cur = head; // 移动指针
    let count = k; // 暂存k 为了不改变k值
    let index = 1; // cur到第几个了
    let RootNode = head; // 总根节点
    let nextRootNode = head; // 下组根节点
    let tail = head;
    let root = null;
    while(count-- && count >= 0) {
        if(index === k) RootNode = cur;
        // 如果已经是这组最后一个了 并且不是刚刚好结束
        if (index % k === 0 && cur !== null) {
            tail.next = cur;
            root = cur;
            tail = nextRootNode;
            nextRootNode = cur.next;
            // 如果恰好是最后一个 结束循环
            count = cur.next === null ? 0 : k; // 又开始第二轮循环
        }
        // 反转后移动指针pre、cur
        let temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
        index++;
        // 如果是k的倍数 且是最后一个
        if(count === 0 && cur === null) {
            tail.next = null;
            break;
        }
        // 如果不是k的倍数 且又是最后一个
        if(cur.next === null && index % k !== 0) {
            // 如果是最后一个 且长度小于k 直接反转返回原链表
            // 逆反转最后一小节不足k的
            while(pre !== root) {
                let temp = pre.next;
                pre.next = cur;
                cur = pre;
                pre = temp;
            }
            if(index < k) {
                return nextRootNode;
            } else {
                tail.next = nextRootNode;
                break;
            }
        }
    }
    return RootNode;
}



发表于 2023-02-08 21:54:52 回复(1)
// 浅用一下递归
function reverseKGroup(head, k) {
  // 定义一个用于翻转指定开始节点和长度区间内节点的函数
  function reversePart(startNode, step, flag) {
    if (startNode == null) return null;
    let curr = startNode.next;
    let prev = startNode;
    for (let i = 0; i < step; i++) {
      // 这种情况用于解决当k值大于剩余节点的个数时,将翻转的节点复原
      if (curr == null) {
        // 这里传flag为true表示用来恢复翻转的节点
        // 因为复原后的curr不为null
        // 所以不能通过curr是否为null来判断是否将satrtNode的next置null
        return reversePart(prev, i, true);
      }
      let temp = prev;
      prev = curr;
      curr = curr.next;
      prev.next = temp;
    }
    // curr != null用于判断是否为结尾
    // !flag 用于判断是否为复原之前的翻转操作
    startNode.next =
      curr != null && !flag ? reversePart(curr, step, false) : null;
    return prev;
  }
  return reversePart(head, k - 1, false);
}

发表于 2022-10-19 22:32:15 回复(0)
/*
 * function ListNode(x){
 *   this.val = x;
 *   this.next = null;
 * }
 */

/**
 *
 * @param head ListNode类
 * @param k int整型
 * @return ListNode类
 */
function reverseKGroup(head, k) {
    // write code here
    let t = head
    let count = 0;
    while (t != null) {
        count++;
        t = t.next;
    }
    if (count < k) {
        return head;
    }
    let number = count / k;
    let cur = head;
    let pre = null;
    let res = head;
    for (let j = 1; j <= number; j++) {
        let xx = cur
        for (let i = 1; i <= k; i++) {
            let temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        if (j === 1) {
            head = pre;
        } else {
            res.next = pre;
        }
        res = xx;
    }
    res.next = cur;
    return head;
}

module.exports = {
    reverseKGroup: reverseKGroup
};

发表于 2022-07-10 19:18:45 回复(0)
/*
 * function ListNode(x){
 *   this.val = x;
 *   this.next = null;
 * }
 */

/**
  * 
  * @param head ListNode类 
  * @param k int整型 
  * @return ListNode类
  */
function reverseKGroup( head ,  k ) {
    // write code here
    let headNode = head
    //当k超过节点数时,直接返回
    for(let i=0;i<k;i++){
        if(headNode == null){
            return head
        }
        headNode = headNode.next
    }
    
    //对k个节点进行逆转(进行k-1此指向转换)
    let cur = head.next
    let pre = head
    for(let i=1;i<k;i++){
        let tmp = cur.next
        cur.next = pre
        pre = cur 
        cur = tmp       
    }
    //递归对下一组k个进行逆转,且每次都是把head指向下一组
    head.next = reverseKGroup(cur,k)
    //返回每一组逆序后实际的头节点(就是当前pre指向的,即每组第k个元素)
    return pre
}
module.exports = {
    reverseKGroup : reverseKGroup
};

发表于 2022-04-03 17:57:16 回复(1)
/*
 * function ListNode(x){
 *   this.val = x;
 *   this.next = null;
 * }
 */

/**
  * 
  * @param head ListNode类 
  * @param k int整型 
  * @return ListNode类
  */
function reverseKGroup( head ,  k ) {
    let tempNode = head;
        for (let i = 0; i < k; i++) {
            // 不足k个,直接返回
            if (tempNode == null) {
                return head;
            }
            tempNode = tempNode.next;
        }
        // reverse
        let dummyNode = {};
        tempNode = head;
        let next = null;
        for (let i = 0; i < k; i++) {
            next = tempNode.next;
            tempNode.next = dummyNode.next;
            dummyNode.next = tempNode;
            tempNode = next;
        }
        // link
        head.next = reverseKGroup(next, k);
        return dummyNode.next;
}
module.exports = {
    reverseKGroup : reverseKGroup
};
发表于 2021-09-12 21:51:54 回复(0)

问题信息

难度:
7条回答 25334浏览

热门推荐

通过挑战的用户